﻿using System;
using System.Collections.Generic;
using UnityEngine;

public sealed class ObjectPool : MonoBehaviour
{
    private static ObjectPool _instance;
    private Dictionary<Component, List<Component>> objectLookup = new Dictionary<Component, List<Component>>();
    private Dictionary<Component, Component> prefabLookup = new Dictionary<Component, Component>();

    public static void Clear()
    {
        instance.objectLookup.Clear();
        instance.prefabLookup.Clear();
    }

    public static int Count<T>(T prefab) where T: Component
    {
        if (instance.objectLookup.ContainsKey(prefab))
        {
            return instance.objectLookup[prefab].Count;
        }
        return 0;
    }

    public static bool IsRecycled<T>(T obj) where T: Component
    {
        return instance.prefabLookup.ContainsKey(obj);
    }

    public static void Recycle<T>(T obj) where T: Component
    {
        if (obj != null)
        {
            if (instance.prefabLookup.ContainsKey(obj))
            {
                instance.objectLookup[instance.prefabLookup[obj]].Add(obj);
                instance.prefabLookup.Remove(obj);
                obj.transform.SetParent(instance.transform);
                obj.gameObject.SetActive(false);
            }
            else
            {
                UnityEngine.Object.DestroyImmediate(obj.gameObject);
            }
        }
    }

    public static T Spawn<T>(T prefab) where T: Component
    {
        return Spawn<T>(prefab, Vector3.zero, Quaternion.identity);
    }

    public static T Spawn<T>(T prefab, Vector3 position) where T: Component
    {
        return Spawn<T>(prefab, position, Quaternion.identity);
    }

    public static T Spawn<T>(T prefab, Vector3 position, Quaternion rotation) where T: Component
    {
        if (!instance.objectLookup.ContainsKey(prefab))
        {
            instance.objectLookup.Add(prefab, new List<Component>());
        }
        T key = null;
        List<Component> list = instance.objectLookup[prefab];
        if (list.Count > 0)
        {
            while ((key == null) && (list.Count > 0))
            {
                key = list[0] as T;
                list.RemoveAt(0);
            }
            if (key != null)
            {
                key.transform.localPosition = position;
                key.transform.localRotation = rotation;
                key.gameObject.SetActive(true);
                instance.prefabLookup.Add(key, prefab);
                return key;
            }
        }
        key = (T) UnityEngine.Object.Instantiate(prefab, position, rotation);
        key.transform.SetParent(instance.transform);
        instance.prefabLookup.Add(key, prefab);
        return key;
    }

    public static ObjectPool instance
    {
        get
        {
            if (_instance == null)
            {
                _instance = new GameObject("_ObjectPool") { transform = { localPosition = Vector3.zero } }.AddComponent<ObjectPool>();
            }
            return _instance;
        }
    }
}

